print(require('dcall'));
print(require('drw'));
print(dlopen,dlsym,dlclose);

function hex(v)
    return string.format("%X",v);
end

function pprintf(fmt,...)
    dcall(printf,fmt,...);
end

-- function double(v)
    -- return v,0;
-- end

local user32 = dlopen("user32.dll");
print(user32);
local MessageBox = dlsym(user32,"MessageBoxA");
print(MessageBox);

--local ret = stdcall(MessageBox,0,"Hello","title",1);

local v1,v2 = double(0.04);
print(hex(v1),hex(v2));
--=====================================================
--long double test
---------------------------------------
--false
dcall(printf,"%llf\n",v1);
---------------------------------------
--true
dcall(printf,"%llf\n",double(0.04));
dcall(printf,"%llf\n",v1,v2);
dcall(printf,"%llf\n",0.04);
--=====================================================

dcall(printf,"%s\n",hex);

pprintf("%s%p\n","hello world!",0x111111);
pprintf("%s%p\n","hello world!",dcall);
pprintf("%s%p\n","hello world!",printf);


--print(hex(ret));
dlclose(user32);

local old = {
    dlopen = dlopen,
    dlsym = dlsym,
};

function dlsym(dll,sym)
    local address = old.dlsym(dll,sym);
    local t = getmetatable(dll);
    local call = dcall;
    if(t and t.call_type)then
        call = t.call_type;
    end
    if(isnull(address))then
        return nil;
    end
    local ms = {
        __call = function(addr,...)
            call(addr,...);
        end
    }
    udsetmetatable(address,ms);
    return address;
end

function dlopen(n,call_type)
    if(call_type=="stdcall")then
        call_type = stdcall;
    elseif(call_type==nil)then
        call_type = dcall;
    end;
    local dll = old.dlopen(n);
    if(isnull(dll))then
        return nil;
    end
    local s = {
        __gc = function(dll)
            print("dlclose ",dll);
            dlclose(dll);
        end,
        __tostring = function(dll)
            local ldata = dpointer(dll);
            return tostring(ldata);
        end,
        --call_type = dcall,
        __setcall = function(dll,n)
            local t = getmetatable(dll);
            if(n=="stdcall")then
                t.call_type = stdcall;
            else
                t.call_type = dcall;
            end
        end,
        __index = function(dll,n)
            return dlsym(dll,n);
        end,
    }
    s.call_type = call_type;
    if(s.__gc)then
        dll = dtouserdata(dll);
    end
    udsetmetatable(dll,s);
    return dll;
end

-------------------------------------------
--stdcall
user32 = dlopen("user32.dll","stdcall");
MessageBox = dlsym(user32,"MessageBoxA");
MessageBox(0,"Hello","title",1);
print(user32.MessageBoxA(0,"Hello","title",1));
user32 = nil;
---------------------------------------------
--cdecl

msvc = dlopen("msvcrt.dll");
print(msvc);
print(msvc.printf);
msvc.printf("%d %d %d\n",1111,2222,3333); --cdecl
printf = msvc.printf;
printf("%f %f\n",0.000004,0.1);
---------------------------------------------

